package com.xiguaji.tiktok.v1.user.log;


import cn.hutool.core.date.DateUtil;
import com.xiguaji.boot.toolkit.HttpUtil;
import com.xiguaji.boot.toolkit.JsonUtil;
import com.xiguaji.tiktok.utils.AspectUtil;
import com.xiguaji.tiktok.utils.CheckMobile;
import com.xiguaji.tiktok.utils.jwt.JwtUser;
import com.xiguaji.tiktok.utils.jwt.JwtUtil;
import com.xiguaji.tiktok.v1.tiktok.permission.repository.UserRoleRepository;
import com.xiguaji.tiktok.v1.user.model.User;
import com.xiguaji.tiktok.v1.user.model.UserOperationLog;
import com.xiguaji.tiktok.v1.user.service.UserLogService;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

/**
 * 路由访问查看
 * @author zzy
 * @Date 2019-07-18 15:25
 */
@Slf4j
@Aspect
@Component
public class UserLogAspect {


    @Autowired
    UserRoleRepository userRoleRepository;

    @Autowired
    JwtUtil jwtUtil;

    @Value("${jwt.head}")
    String authorized;

    @Autowired
    UserLogService userLogService;

    @Pointcut(value = "@annotation(com.xiguaji.tiktok.v1.user.log.Operation)")
    public void Pointcut(){
    }

    @Around(value = "Pointcut()")
    public Object printInfo(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        val annotation = AspectUtil.INSTANCE.getMethod(proceedingJoinPoint).getAnnotation(Operation.class);
        Method currentMethod = AspectUtil.INSTANCE.getMethod(proceedingJoinPoint);
        String className = AspectUtil.INSTANCE.getClassName(proceedingJoinPoint);
        UserOperationLog userOperationLog = new UserOperationLog();
        userOperationLog.setDateCode(Integer.parseInt(DateUtil.format(new Date(),"yyyyMMdd")));
        userOperationLog.setRequestIp(HttpUtil.getIp());
        userOperationLog.setRequestType(HttpUtil.getMethod());
        userOperationLog.setRequestParams(URLDecoder.decode(Arrays.toString(proceedingJoinPoint.getArgs()),"UTF-8"));
        userOperationLog.setRequestUrl(HttpUtil.getRequestUrl());
        userOperationLog.setOperationMethod(className + currentMethod.getName());
        userOperationLog.setOperation(annotation.value());
        userOperationLog.setMobile(CheckMobile.check());
        // userOperationLog.setPerId("");
        String param = "";
        try{
            if(StringUtils.isNotEmpty(annotation.fetchParam())){
                if(annotation.paramType() == ParamsType.PARAMS){
                    Map<String, String[]> parameterMap = HttpUtil.getRequest().getParameterMap();
                    param = parameterMap.get(annotation.fetchParam()).toString();
                }else if(annotation.paramType() == ParamsType.JSON){
                    val parameterMap = JsonUtil.jsonParse(Map.class, URLDecoder.decode(proceedingJoinPoint.getArgs()[0].toString(),"UTF-8"));
                    param = parameterMap.get(annotation.fetchParam()).toString();
                }else if(annotation.paramType() == ParamsType.URL){
                    val mappingAnnotation = AspectUtil.INSTANCE.getMethod(proceedingJoinPoint).getAnnotation(RequestMapping.class);
                    // 截取不存在占位符的Mapping
                    String mappingUrl = mappingAnnotation.value()[0].substring(0,mappingAnnotation.value()[0].indexOf("{"));
                    // 获取占位符中的URL
                    String url = userOperationLog.getRequestUrl().substring(userOperationLog.getRequestUrl().indexOf(mappingUrl));
                    String [] params = url.split("/");
                    String [] mappings = mappingAnnotation.value()[0].substring(
                            mappingAnnotation.value()[0].indexOf(mappingUrl)
                    ).split("/");
                    for (int i = 0; i < mappings.length; i++) {
                        if(mappings[i].contains("{")&&mappings[i].contains(annotation.fetchParam())){
                            param = params[i];
                        }
                    }
                }
            }
        }catch (Exception e){
            log.error("record Operation log error!",e);
        }
        userOperationLog.setDynamicId(param);
        userOperationLog.setCreateBy("System Operation Log!");
        userOperationLog.setUpdateBy("System Operation Log!");
        try{

            return proceedingJoinPoint.proceed();
        }catch (Exception e){
            StringWriter stringWriter = new StringWriter();
            e.printStackTrace(new PrintWriter(stringWriter));
            userOperationLog.setException(stringWriter.toString());
            throw e;
        }finally {
            userOperationLog.setUserId(getUser() == null ?0:getUser().getId());
            userLogService.save(userOperationLog);
        }

    }


    private User getUser(){
        String token = HttpUtil.getCookie(authorized);

        if(StringUtils.isEmpty(token)){
            return null;
        }

        JwtUser jwtUser = jwtUtil.getJwtUser(token);
        if(null == jwtUser){
            return null;
        }

        return JsonUtil.jsonParse(User.class,JsonUtil.parseJson(jwtUser.getUser()));
    }
}
